package aufgabe_2_test.try02;

import static akka.actor.Actors.poisonPill;
import static akka.actor.Actors.remote;
import static aufgabe_2_test.try02.RhoMessage.MsgType.*;
import java.math.BigInteger;

import akka.actor.ActorRef;
import akka.actor.UntypedActor;

public class Worker extends UntypedActor{
	private static int id = 1;
	private static int port = 2000;
	public int workerId;
	/**
	 * Number in question of being factorized
	 */
	private BigInteger n;
	/**
	 * working thread
	 */
	private PollardInThread pollardThread;
	/**
	 * referenz to the master
	 */
	ActorRef master;
	/**
	 * cnt of RhoCycles
	 */
	private BigInteger cnt;
	/**
	 * computation time
	 */
	private long cpt;
	/**
	 * increments the counter for Rhocylces with c
	 * @param c value to increment
	 */
	public void incCount(BigInteger c){
		cnt = cnt.add(c);
	}
	
	public Worker() {
		workerId = id++;
		master = null;
		pollardThread = null;
		cnt = BigInteger.ZERO;
		cpt = 0;
	}
	
	@Override
	public void onReceive(Object o) throws Exception {
		if(o instanceof RhoMessage){
			this.master = getContext().getSender().get();
			RhoMessage rm = (RhoMessage) o;
			if(pollardThread != null){ // let old thread sleep
				pollardThread.setRunning(false);
				pollardThread.tp.join();
				pollardThread = null;
			}
			n = rm.getN();
			if(rm.mt == RhoRequestWorker){ //start working 
				System.out.println("RhoRequestWorker  worker:" +workerId);
			}
			if(rm.mt == RhoGoSleep){ // send status before going to sleep
				master.tell(new RhoMessage(cnt,RhoGetStatus,true,cpt),getContext());
				getContext().tell(poisonPill());
			}else{// start Rho Thread
				BigInteger id = PollardInThread.generateNewA(n,workerId);
				System.out.println(workerId + " -> " + id);
				pollardThread = new PollardInThread(this,n,id);
				Thread t = new Thread(pollardThread);
				pollardThread.setThread(t);
				t.setDaemon(true);
				t.start();
			}
		}
	}
	/**
	 * actual calculation of prime is complete, inform master 
	 * @param res message which will be send to the master
	 */
	public void calcComplete(RhoMessage res){
		System.out.println(workerId + " " + res);
		master.tell(res);
	}

	public static void main(String[] args){
		remote().start("lab23", port);
		System.out.println("Haupt-Worker-Actor gestartet");
	}
	/**
	 * adds the time l to the computation time
	 * @param l computation time which should be added to the actual time
	 */
	public void updateTime(long l) {
		cpt+=l;
	}
}
